﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;

using ProjectBase.Core;

using Survey.Common;
using Survey.Common.Validation;

namespace Survey.Business
{
    public class ReferenceRule<TItem, TReference> : RuleBase, IValidationRule<TItem>
        where TItem : class
        where TReference : class
    {
        #region members
        private readonly Func<TItem, TReference> _compiledExpression;
        string _propertyName;
        #endregion members

        #region Constructor
        public ReferenceRule(Expression<Func<TItem, TReference>> expression)
        {
            Contract.Requires(expression.Is());

            var body = expression.Body as MemberExpression;
            if (body.IsNull())
            {
                throw new NotSupportedException(
                    "Provided 'Expression<Func<TITem, TReference>>' must be of a 'ExpressionType.MemberAccess' (ReferenceRule). ");
            }
            _propertyName = body.Member.Name;
            _compiledExpression = expression.Compile();
        }
        #endregion Constructor

        #region Validate

        public virtual ValidationResult Validate(TItem item, out ValidationMessage message)
        {
            message = null;

            // item cannot be null
            if (item.IsNull())
            {
                message = new ValidationMessage(Str.Messages.NullInsteadOfEntityProvided1)
                {
                    EntityName,
                };
                return ValidationResult.Error;
            }

            var result = CompiledExpression.Invoke(item);

            // NOT Required string could be null or empty
            if (result.Is())
            {
                return ValidationResult.IsValid;
            }

            // referenced property is NULL
            var entity = item as IPersistentObject;
            var itemId = entity.IsNull()
                ? "N/A"
                : entity.IsTransient() ? "new" : entity.IDToDisplay;

            message = new ValidationMessage(Str.Messages.MissingProperty2)
            {
                itemId,
                PropertyName.GetLocalized(EntityName),
            };
            return ValidationResult.Error;
        }

        #endregion Validate

        #region properties
        protected virtual Func<TItem, TReference> CompiledExpression
        {
            get { return _compiledExpression; }
        }
        protected virtual string PropertyName
        {
            get { return _propertyName; }
            set { _propertyName = value; }
        }
        protected virtual string EntityName { get { return typeof(TItem).Name; } }
        #endregion properties
    }
}